﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Castle.DynamicProxy;
using System.Reflection;
using JackyCode.Mock.Exceptions;
using Castle.Core.Interceptor;

namespace JackyCode.Mock.Test
{
    [TestFixture]
    public class TestMockInterceptorImpl
    {
        private class MockDataStub : IMockData
        {
            public IDictionary<MethodData, object> methodDatas;

            public IList<int> CallGetReturnValMethodWithListObjAndMethodInfoArgTimes { get; set; }


            public MockDataStub()
            {
                methodDatas = new Dictionary<MethodData, object>();
                CallGetReturnValMethodWithListObjAndMethodInfoArgTimes = new List<int>();
            }

            public object GetReturnVal(MethodData methodInfo)
            {
                return true;
            }

            public bool Contains(MethodData methodInfo)
            {
                return false;
            }


            public int Count
            {
                get 
                {
                    return methodDatas.Count;
                }
            }

            public int GetExecuteTimes(MethodData methodInfo)
            {
                return 0;
            }

            public void Merge(MethodData methodData, object returnVal)
            {

            }


            public object GetReturnVal(MethodInfo methodInfo, IList<object> arguments)
            {
                CallGetReturnValMethodWithListObjAndMethodInfoArgTimes.Add(1);
                return true;
            }

            public object GetParameterVal(int pIndex, MethodInfo methodInfo, IList<object> arguments)
            {
                return null;
            }


            public void SetOutParamterVal(MethodInfo methodInfo, IList<object> arguments)
            {
                if (arguments.Count > 1)
                {
                    arguments[1] = "Output";
                }
            }
        }

        private ProxyGenerator proxyGenerator = new ProxyGenerator();
        private MockDataStub mockData;
        private IMockInterceptor interceptor;
        private IService iProxy;
        private Service cProxy;

        [SetUp]
        public void Initialize()
        {
            mockData = new MockDataStub();
            interceptor = new MockInterceptorImpl(mockData);
            iProxy = proxyGenerator.CreateInterfaceProxyWithoutTarget<IService>(interceptor);
            cProxy = proxyGenerator.CreateClassProxy<Service>(interceptor);
        }

        [Test]
        public void TestCallClassVirMethod()
        {
            Assert.IsTrue(cProxy.CReturnBoolMethod());
            Assert.AreEqual(1, mockData.CallGetReturnValMethodWithListObjAndMethodInfoArgTimes.Count);
        }

        [Test]
        public void TestCallInterfaceMethod()
        {
            Assert.IsTrue(iProxy.IReturnBoolMethod());
            Assert.AreEqual(1, mockData.CallGetReturnValMethodWithListObjAndMethodInfoArgTimes.Count);
        }

        [Test]
        public void TestCallNonVirMethod()
        {
            Assert.AreEqual("ReturnStrNonVirMethod", cProxy.ReturnStrNonVirMethod());
            Assert.AreEqual(0, mockData.CallGetReturnValMethodWithListObjAndMethodInfoArgTimes.Count);
        }

        [Test]
        public void TestCallMethodWithOutParameter()
        {
            string result;
            iProxy.OutMethod("Input", out result);
            Assert.AreEqual("Output", result);
        }
    }

}
